route.ts 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. import { NextRequest, NextResponse } from "next/server";
  2. import { getServerSession } from "next-auth";
  3. import { authOptions } from "@/lib/auth";
  4. import { prisma } from "@/lib/prisma";
  5. import { generateJitsiToken, isJitsiJWTConfigured } from "@/lib/jitsi-jwt";
  6. import { config } from "@/lib/config";
  7. // GET /api/appointments/[id]/jitsi-token - Generar JWT token para Jitsi
  8. export async function GET(
  9. request: NextRequest,
  10. { params }: { params: Promise<{ id: string }> }
  11. ) {
  12. try {
  13. const { id } = await params;
  14. const session = await getServerSession(authOptions);
  15. if (!session?.user?.id) {
  16. return NextResponse.json({ error: "No autorizado" }, { status: 401 });
  17. }
  18. // Verificar si JWT está configurado
  19. if (!isJitsiJWTConfigured()) {
  20. return NextResponse.json(
  21. {
  22. error: "Jitsi JWT no está configurado",
  23. useJWT: false,
  24. domain: config.jitsi.domain,
  25. },
  26. { status: 200 }
  27. );
  28. }
  29. const user = await prisma.user.findUnique({
  30. where: { id: session.user.id },
  31. });
  32. if (!user) {
  33. return NextResponse.json(
  34. { error: "Usuario no encontrado" },
  35. { status: 404 }
  36. );
  37. }
  38. const appointment = await prisma.appointment.findUnique({
  39. where: { id },
  40. include: {
  41. paciente: true,
  42. medico: true,
  43. },
  44. });
  45. if (!appointment) {
  46. return NextResponse.json(
  47. { error: "Cita no encontrada" },
  48. { status: 404 }
  49. );
  50. }
  51. // Validar que el usuario sea parte de la cita
  52. const isPatient = appointment.pacienteId === user.id;
  53. const isDoctor = appointment.medicoId === user.id;
  54. if (!isPatient && !isDoctor) {
  55. return NextResponse.json(
  56. { error: "No tienes acceso a esta cita" },
  57. { status: 403 }
  58. );
  59. }
  60. // Validar que la cita esté aprobada o completada
  61. if (
  62. appointment.estado !== "APROBADA" &&
  63. appointment.estado !== "COMPLETADA"
  64. ) {
  65. return NextResponse.json(
  66. { error: "Solo se pueden acceder a citas aprobadas" },
  67. { status: 400 }
  68. );
  69. }
  70. // Validar que tenga fecha asignada
  71. if (!appointment.fechaSolicitada) {
  72. return NextResponse.json(
  73. { error: "La cita no tiene fecha asignada" },
  74. { status: 400 }
  75. );
  76. }
  77. // Validar el tiempo: permitir unirse 15 minutos antes hasta 1 hora después
  78. const now = new Date();
  79. const appointmentTime = new Date(appointment.fechaSolicitada);
  80. const fifteenMinutesBefore = new Date(
  81. appointmentTime.getTime() - 15 * 60 * 1000
  82. );
  83. const oneHourAfter = new Date(
  84. appointmentTime.getTime() + 60 * 60 * 1000
  85. );
  86. if (now < fifteenMinutesBefore) {
  87. const minutesUntil = Math.floor(
  88. (appointmentTime.getTime() - now.getTime()) / (60 * 1000)
  89. );
  90. return NextResponse.json(
  91. {
  92. error: "Aún no es tiempo de la cita",
  93. message: `La cita será en ${minutesUntil} minutos. Podrás unirte 15 minutos antes.`,
  94. minutesUntil,
  95. },
  96. { status: 400 }
  97. );
  98. }
  99. if (now > oneHourAfter) {
  100. return NextResponse.json(
  101. { error: "La cita ya finalizó" },
  102. { status: 400 }
  103. );
  104. }
  105. // Determinar nombre de sala
  106. const roomName = appointment.roomName || `appointment-${id}`;
  107. // Si no existe roomName, crearlo
  108. if (!appointment.roomName) {
  109. await prisma.appointment.update({
  110. where: { id },
  111. data: { roomName },
  112. });
  113. }
  114. // Generar JWT token
  115. const userName = `${user.name} ${user.lastname || ""}`.trim();
  116. const isModerator = user.role === "DOCTOR" || user.role === "ADMIN";
  117. const avatarUrl = user.profileImage || undefined;
  118. const token = generateJitsiToken(
  119. user.id,
  120. userName,
  121. user.email || undefined,
  122. roomName,
  123. isModerator,
  124. avatarUrl,
  125. 7200 // 2 horas de expiración
  126. );
  127. return NextResponse.json({
  128. token,
  129. roomName,
  130. domain: config.jitsi.domain,
  131. userName,
  132. isModerator,
  133. useJWT: true,
  134. });
  135. } catch (error) {
  136. console.error("Error al generar JWT token de Jitsi:", error);
  137. return NextResponse.json(
  138. { error: "Error al generar token de autenticación" },
  139. { status: 500 }
  140. );
  141. }
  142. }